#include "picture.h"

Picture::Picture()
{
	position = glm::vec3(0, 0, 0);
	rotation = 0;

	widthInPixels = 1024;
	heightInPixels = 600;

	source = glm::ivec2(0, 0);
	destination = glm::ivec2(0, 0);
		
	this->vertex_array_handle = (GLuint) -1;
	this->vertex_coordinate_handle = (GLuint) -1;

	image_container = new ILContainer();
}

Picture::~Picture()
{
	this->TakeDown();
}

void Picture::SetSource(glm::ivec2 source)
{
	this->source = source;
}

void Picture::SetDestination(glm::ivec2 destination)
{
	this->destination = destination;
}

bool Picture::Initialize()
{
	if (!image_container->Initialize("puppy.jpg"))
	{
		return false;
	}

	shader = new Shader();
	frameBuffer = new FrameBufferObject();

	bool initialized = false;

	if (!shader->Initialize("stub.vert", "stub.frag"))
	{
		return false;
	}

	// after the image in the picture frame is warped, the warped picture becomes
	// the new original. Subsequent warps then work on top of that first warp, and
	// so on. That's why there are two color attachments.
	if (!frameBuffer->Initialize(glm::ivec2(widthInPixels, heightInPixels), 2, true))
	{
		return false;
	}
	
	return true;
}

void Picture::TakeDown()
{
	this->shader->TakeDown();
	this->frameBuffer->TakeDown();
}

void Picture::Display()
{
	if (this->sh_vertices.size() == 0)
	{
		// the points form a square with center (0, 0)
		this->sh_vertices.push_back(glm::vec2(-1.0f, -1.0f));
		this->sh_vertices.push_back(glm::vec2( 1.0f, -1.0f));
		this->sh_vertices.push_back(glm::vec2( 1.0f,  1.0f));
		this->sh_vertices.push_back(glm::vec2(-1.0f,  1.0f));

		// reference: http://www.opengl.org/sdk/docs/man/xhtml/glGenBuffers.xml
		// reference: http://www.opengl.org/sdk/docs/man/xhtml/glBindBuffer.xml
		// reference: http://www.opengl.org/sdk/docs/man/xhtml/glBufferData.xml
		glGenBuffers(1, &this->vertex_coordinate_handle);
		glBindBuffer(GL_ARRAY_BUFFER, this->vertex_coordinate_handle);
		glBufferData(GL_ARRAY_BUFFER, this->sh_vertices.size() * sizeof(glm::vec2), &this->sh_vertices[0], GL_STATIC_DRAW);

		// reference: http://www.opengl.org/sdk/docs/man/xhtml/glGenVertexArrays.xml
		// reference: http://www.opengl.org/sdk/docs/man3/xhtml/glBindVertexArray.xml
		// reference: http://www.opengl.org/sdk/docs/man/xhtml/glEnableVertexAttribArray.xml
		glGenVertexArrays(1, &this->vertex_array_handle);
		glBindVertexArray(this->vertex_array_handle);
		glEnableVertexAttribArray(0);

		// reference: http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribPointer.xml
		//glBindBuffer(GL_ARRAY_BUFFER, this->vertex_coordinate_handle);
		glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLubyte *) NULL);
		glBindVertexArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}

	// reference: http://www.opengl.org/sdk/docs/man/xhtml/glUniform.xml
	shader->Use();
	glUniform1i(shader->GetImageMapHandle(), 0);
	glUniform2i(shader->GetSizeHandle(), widthInPixels, heightInPixels);
	glUniform2i(shader->GetSourceHandle(), source.x, source.y);
	glUniform2i(shader->GetDestinationHandle(), destination.x, destination.y);

	// render to the frame buffer
	// reference: http://www.opengl.org/sdk/docs/man/xhtml/glDrawArrays.xml
	frameBuffer->Bind();
	glViewport(0, 0, frameBuffer->GetSize().x, frameBuffer->GetSize().y);
	glBindVertexArray(this->vertex_array_handle);
	glDrawArrays(GL_QUADS, 0, (GLsizei) this->sh_vertices.size());
	frameBuffer->Unbind();
	glUseProgram(0);

	glBindTexture(GL_TEXTURE_2D, frameBuffer->GetTextureHandles()[0]);
	glEnable(GL_TEXTURE_2D);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	//glOrtho(-1, 1, -1, 1, 1, 10);
	gluPerspective(60, frameBuffer->GetSize().x / frameBuffer->GetSize().y, 1, 10);
	glViewport(0, 0, frameBuffer->GetSize().x, frameBuffer->GetSize().x);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0.0f, 0.0f, -5.5f);
	glRotatef(45, 0, 1, 0);

	glBegin(GL_QUADS);
	glTexCoord2d(0, 0);
	glVertex2d(-1, -1);
	glTexCoord2d(1, 0);
	glVertex2d(1, -1);
	glTexCoord2d(1, 1);
	glVertex2d(1, 1);
	glTexCoord2d(0, 1);
	glVertex2d(-1, 1);
	glEnd();

	glBindTexture(GL_TEXTURE_2D, 0);
	glBindVertexArray(0);

	glutSwapBuffers();
}

//Frame buffer code
//#include "Jumbotron.h"
//
//#include <iostream>
//using namespace std;
////Creates a generic jumbotron
//Jumbotron::Jumbotron()
//{
//	Jumbotron(300,300,800,800);
//}
//Jumbotron::Jumbotron(double w, double h, double screenW, double screenH)
//{
//	window_width = screenW; // The width of our window
//	window_height = screenH; // The height of our window
//	width = w;	// The width of our jumbotron
//	height = h;	// The height of our jumbotron
//}
////Initialize all the texture and rendering stuff
//void Jumbotron::init() {
//	fbo = 1;
//	fbo_depth=1;
//	fbo_texture=1;
//
//	glGenFramebuffersEXT(1, &fbo); // Generate one frame buffer and store the ID in fbo
//	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer
//	glGenRenderbuffersEXT(1, &fbo_depth); // Generate one render buffer and store the ID in fbo_depth
//	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth); // Bind the fbo_depth render buffer
//	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, window_width, window_height); // Set the render buffer storage to be a depth component, with a width and height of the window
//	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo_depth); // Set the render buffer of this buffer to the depth buffer
//
//	glGenTextures(1, &fbo_texture); // Generate one texture
//	glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind the texture fbo_texture
//	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, window_width, window_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // Create a standard texture with the width and height of our w
//
//	//TEXTURE SETTINGS FOR GOOD RENDERING, NO LINES
//	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//
//	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
//	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0);
//	GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
//	if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
//		throw std::string("Frame buffer failed to initialize properly");
//	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
//}
//
//bool bindTexture;
//bool bindDepth;
//void Jumbotron::bindFBO()
//{ 
//	//Enable 2D_TEXTURE
//	if((!glIsEnabled(GL_TEXTURE_2D)) ? bindTexture = false : bindTexture = true)
//		glEnable(GL_TEXTURE_2D);
//	if((!glIsEnabled(GL_DEPTH_TEST)) ? bindDepth = false : bindDepth = true)
//		glEnable(GL_DEPTH_TEST);
//	// Enable depth testing
//
//	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // Bind our frame buffer for rendering
//	glPushAttrib(GL_VIEWPORT_BIT);
//	glViewport(0,0,window_width,window_height);
//}
//void Jumbotron::unBindFBO()
//{
//	glPopAttrib();
//	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture
//
//	if(!bindTexture)
//		glDisable(GL_TEXTURE_2D);
//	if(!bindDepth)
//		glDisable(GL_DEPTH_TEST);
//}
////Draws the jumbotron at a certain pos with a certain direction!
//void Jumbotron::Draw (Vector3 * centOfPos, double ang) {
//
//	glPushMatrix();
//	//Translate to a certain position
//	glTranslated(centOfPos->getX(),centOfPos->getY(),centOfPos->getZ());
//	//Rotate based on on our angle passed. Precalculated
//	glRotated(ang,0.0,1.0,0.0);
//	glPushMatrix();//Draw our support spoke
//	utilities::setLighting(1.0,0.5,0.2,1.0);
//	glTranslated(-supportSize-1,0,0);
//	glRotated(90,1.0,0.0,0.0);
//	glutSolidCylinder(supportSize,2000,30,30);
//	glPopMatrix();
//	glPopMatrix();
//
//	glColor3d(1.0,1.0,1.0);
//
//	bool texture;
//	bool depth;
//	bool lighting;
//
//	//Enable 2D_TEXTURE
//	if(glIsEnabled(GL_TEXTURE_2D) ? texture = false : texture = true)
//		glEnable(GL_TEXTURE_2D);
//	// Enable depth testing
//	if(glIsEnabled(GL_DEPTH_TEST) ? depth = true : depth = false)
//		glDisable(GL_DEPTH_TEST);
//	//Enable Lighting
//	if(glIsEnabled(GL_LIGHTING) ? lighting = true : lighting = false)
//		glDisable(GL_LIGHTING);
//
//	glPushMatrix();
//		glTranslated(centOfPos->getX(),centOfPos->getY(),centOfPos->getZ());
//		glRotated(ang,0.0,1.0,0.0);
//
//		glBindTexture(GL_TEXTURE_2D, fbo_texture); // Bind our frame buffer texture
//
//		glBegin(GL_QUADS);
//		glTexCoord2f(1.0f, 0.0f);
//		glVertex3d(0.0,-(height/2.0),-(width/2.0)); // The bottom left corner
//
//		glTexCoord2f(1.0f, 1.0f);
//		glVertex3f(0.0, (height/2.0), -(width/2.0)); // The top left corner
//
//		glTexCoord2f(0.0f, 1.0f);
//		glVertex3f(0.0, (height/2.0),(width/2.0)); // The top right corner
//
//		glTexCoord2f(0.0f, 0.0f);
//		glVertex3f(0.0, -(height/2.0), (width/2.0)); // The bottom right corner
//		glEnd();
//	glPopMatrix();
//
//	if(lighting)
//		glEnable(GL_LIGHTING);
//	if(!texture)
//		glDisable (GL_TEXTURE_2D);
//	if(depth)
//		glEnable(GL_DEPTH_TEST);
//
//	glBindTexture(GL_TEXTURE_2D, 0); // Unbind any textures
//}
